package com.yx.filesystem.storage;

import java.math.BigInteger;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

public final class Server {
	private static Server instance = null;
	Node serverNode = null;
	BackupDaemonService backupDaemonService = null;
	SocketServer socketServer = null;
	Hashtable<String, BigInteger> storageSaveState = new Hashtable<String, BigInteger>();

	private Server() {
	}

	public static Server get() {
		if (instance == null) {
			instance = new Server();
		}
		return instance;
	}

	public Node getServerNode() {
		return serverNode;
	}

	public BackupDaemonService getBackupDaemonService() {
		return backupDaemonService;
	}

	public Hashtable<String, BigInteger> getStorageSaveState() {
		return storageSaveState;
	}

	public synchronized void setStorageSaveState(String nodeId,
			BigInteger fileTotalNumber) {
		if (storageSaveState.containsKey(nodeId)) {
			if (fileTotalNumber.compareTo(storageSaveState.get(nodeId)) > 0) {
				storageSaveState.put(nodeId, fileTotalNumber);
			}
		} else {
			storageSaveState.put(nodeId, fileTotalNumber);
		}
	}

	public void start(Node serverNode) throws Exception {
		this.serverNode = serverNode;
		List<String> saveNodeList = Archive.getStorageSaveNodes();
		for (String saveNodeId : saveNodeList) {
			BigInteger fileTatolNumber = Archive.getMaxArchive(saveNodeId).getFileTotalNumber();
			if (!saveNodeId.equals(serverNode.getId())) {
				if (isBadFile(saveNodeId, fileTatolNumber.toString())) {
					fileTatolNumber = fileTatolNumber.subtract(new BigInteger(
							"1"));
				}
			}
			setStorageSaveState(saveNodeId, fileTatolNumber);
		}
		backupDaemonService = new BackupDaemonService(serverNode);
		socketServer = new SocketServer(serverNode.getPort());
	}

	private boolean isBadFile(String saveNodeId, String fileTatolNumber) {
		long endTimeStamp = Long.parseLong(fileTatolNumber.substring(0, 14));
		long endFileNumber = Long.parseLong(fileTatolNumber.substring(14));
		Archive file = new Archive(saveNodeId, endTimeStamp, endFileNumber);
		if (file.exists() && file.isBadFile()) {
			return true;
		}
		return false;
	}

	public static void main(String[] args) {
		Properties pps = System.getProperties();
		System.out.println("JVM file.encoding="
				+ pps.getProperty("file.encoding"));
		int TCPBuffer=getParmInt(args,"TCPBuffer");
		if(TCPBuffer>0){
			SocketServer.SOCKET_BUFFER_SIZE=TCPBuffer*1024;
		}
		int IOBuffer=getParmInt(args,"IOBuffer");
		if(IOBuffer>0){
			SocketServer.BUFFER_SIZE=IOBuffer*1024;
		}
		System.out.println("I/O buffer size:"+SocketServer.BUFFER_SIZE+"bytes");
		int thread=getParmInt(args,"thread");
		if(thread>0){
			SocketServer.THREAD_PPPL_SIZE=thread;
		}
		System.out.println("Thread pool size:"+SocketServer.THREAD_PPPL_SIZE);
		int port  = getParmInt(args, "port");
		if (port <= 0) {
			port=10086;
			//System.out.println("INCORRECT port parm: port=9997");
			//System.exit(0);
		}		
		String hostIp = "";
		try {
			hostIp = getHostIp();
		} catch (Exception e) {
			System.out.println("Error to get Server Ip:" + e);
			System.exit(0);
		}
		List<String> idParms=getParmStr(args,"id");
		if(idParms.size()<1||idParms.get(0).trim().length()!=5){
			System.out.println("INCORRECT Server ID,Please set parm:id=[node id]");
			System.exit(0);
		}
		String id=idParms.get(0).trim();
		System.out.println("Server Node "+id+"：" + hostIp + ":" + port);
		Node serverNode=null;
		try{
			serverNode = new Node(id,hostIp, port);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
		List<String> backupParms=getParmStr(args,"backup");
		if(backupParms.size()<1){
			System.out.println("StorageServer need At least one BackupServer, For Example:backup=192.168.9.24:9997");
			System.exit(0);
		}
		for (int i = 0; i < backupParms.size(); i++) {
			String backupAddress = backupParms.get(i);
			String[] addressArray=backupAddress.split("\\:");
			String backId=addressArray[0];			
			String backupAddressIp = addressArray[1];
			int backupAddressPort = Integer.parseInt(addressArray[2]);
			try{
				Node backuoNode = new Node(backId,backupAddressIp, backupAddressPort);
				serverNode.addBachupNodes(backuoNode);
			}catch(Exception e){
				e.printStackTrace();
				System.exit(0);
			}
		}
		
		try {
			Server.get().start(serverNode);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

	private static List<String> getParmStr(String[] args, String key) {
		List<String> parm = new ArrayList<String>();
		for (int i = 0; i < args.length; i++) {
			String arg = args[i].trim();
			if (arg.startsWith(key + "=")) {
				parm.add(arg.substring(key.length() + 1));
			}
		}
		return parm;
	}

	private static int getParmInt(String[] args, String key) {
		try {
			List<String> parm = new ArrayList<String>();
			for (int i = 0; i < args.length; i++) {
				String arg = args[i].trim();
				if (arg.startsWith(key + "=")) {
					return Integer.parseInt(arg.substring(key.length() + 1));
				}
			}
			return -1;
		} catch (Exception e) {
			return -1;
		}
	}

	public static String getHostIp() throws Exception {
		String ip = InetAddress.getLocalHost().getHostAddress();
		return ip;
	}

}
